package gnss

import (
	"dgo/goutils/utils"
	"fmt"
	"sort"
	"time"
)

// Rinex一个历元数据
/***
  用RtcmMsmEpoch
*/
type EpochRinexObs struct {
	Time   time.Time
	TOW    int64
	ObsMap map[string]*RinexObs // RinexObs

	// 计算LLI
	PreTOW int64
	PreMap map[string]*RinexObs
}

func NewEpochRinexObs() *EpochRinexObs {
	rval := &EpochRinexObs{
		ObsMap: make(map[string]*RinexObs),
	}
	return rval
}

func (this *EpochRinexObs) GetEpochRinexObs(prn string) *RinexObs {
	if len(prn) == 0 {
		return nil
	}
	rval := this.ObsMap[prn]
	if rval == nil {
		rval = NewRinexObs()
		rval.Prn = prn
		if prn[0] == 'G' {
			rval.Sys = SYS_GPS
		} else if prn[0] == 'C' {
			rval.Sys = SYS_BD
		} else if prn[0] == 'N' {
			rval.Sys = SYS_GLO
		} else {
			rval.Sys = SYS_GPS
		}
		this.ObsMap[prn] = rval
	}
	return rval
}

func (this *EpochRinexObs) CheckGetPrnObs(prn string, sys byte) *RinexObs {
	if len(prn) == 0 {
		return nil
	}
	rval := this.ObsMap[prn]
	if rval == nil {
		rval = NewRinexObs()
		rval.Prn = prn
		rval.Sys = sys
		this.ObsMap[prn] = rval
	}
	return rval
}

func (this *EpochRinexObs) Clear() {
	this.ObsMap = make(map[string]*RinexObs)
	this.PreMap = nil
	this.PreTOW = 0

}

func (this *EpochRinexObs) Save2Pre() {
	this.PreMap = this.ObsMap
	this.PreTOW = this.TOW
}

func (this *EpochRinexObs) Reset() {

	this.ObsMap = make(map[string]*RinexObs)
}

func (this *EpochRinexObs) AddMsm(msm *RtcmMsm) {
	this.TOW = int64(msm.Header.TOW)
	// 循环卫星
	var i, j byte
	for i = 0; i < msm.Header.SatN; i++ {
		prnId := msm.Header.Sats[i]
		strPrn := GetPrnStrCode(prnId, msm.Sys)
		prnO := this.CheckGetPrnObs(strPrn, msm.Sys)
		v := msm.ObsV[i]
		if v == nil {
			panic(fmt.Sprintf("prn:%s, sys:%d obs[%d] is nil!\r\n", strPrn, msm.Sys, i))
		}

		// 循环信号
		for j = 0; j < msm.Header.SigN; j++ {
			iSign := msm.Header.Sigs[j]

			if iSign < 0 || iSign >= 31 {
				panic(fmt.Sprintf("prn:%s, sys:%d sign:%d is invalid! ", strPrn, msm.Sys, iSign))
			}

			if v == nil || int(j) > len(v.Snr)-1 {
				panic(fmt.Sprintf("prn:%s, sys:%d sign:%d MSM SNR[%d] is invalid! ", strPrn, msm.Sys, iSign, j))
			}
			prnO.Snr[iSign] = v.Snr[j]
			prnO.L[iSign] = v.L[j]
			prnO.LokT[iSign] = v.LTI[j]
			prnO.HalfC[iSign] = v.HalfC[j]
			prnO.PseV[iSign] = v.PseV[j]
			prnO.Dop[iSign] = v.Doppler[j]
		}
	}
}

/*
*
返回写入的卫星颗数
*/
func (this *EpochRinexObs) WriteRinex3String(signHeader *RinexHeader, sb *utils.BytesBuilder) int {
	// 排序SN
	prns := make([]string, 0)
	for k, _ := range this.ObsMap {
		prns = append(prns, k)
	}
	sort.Strings(prns)

	// 根据DF407
	var fn_lli_a = func(v int) (int, int) {
		if v >= 0 && v <= 63 {
			return 1, v
		} else if v <= 95 {
			return 2, 2*v - 64
		} else if v <= 127 {
			return 4, 4*v - 256
		} else if v <= 159 {
			return 8, 8*v - 768
		} else if v <= 191 {
			return 16, 16*v - 2048
		} else if v <= 223 {
			return 32, 32*v - 5120
		} else if v <= 255 {
			return 64, 64*v - 12288
		} else if v <= 287 {
			return 128, 128*v - 28672
		} else if v <= 319 {
			return 256, 256*v - 65536
		} else if v <= 351 {
			return 512, 512*v - 147456
		} else if v <= 383 {
			return 1024, 1024*v - 327680
		} else if v <= 415 {
			return 2048, 2048*v - 720896
		} else if v <= 447 {
			return 4096, 4096*v - 1572864
		} else if v <= 479 {
			return 8192, 8192*v - 3407872
		} else if v <= 511 {
			return 16384, 16384*v - 7340032
		} else if v <= 543 {
			return 32768, 32768*v - 15728640
		} else if v <= 575 {
			return 65536, 65536*v - 33554432
		} else if v <= 607 {
			return 131072, 131072*v - 71303168
		} else if v <= 639 {
			return 262144, 262144*v - 150994944
		} else if v <= 671 {
			return 524288, 524288*v - 318767104
		} else if v <= 703 {
			return 1048576, 1048576*v - 671088640
		} else if v == 704 {
			return 2097152, 2097152*v - 1409286144
		} else {
			return 0, 0
		}

	}

	for _, k := range prns {
		robs := this.ObsMap[k]
		signh := signHeader.CHeader
		if robs.Prn[0] == 'C' {
			signh = signHeader.CHeader
		} else if robs.Prn[0] == 'G' {
			signh = signHeader.GHeader
		} else if robs.Prn[0] == 'R' {
			signh = signHeader.GloHeader
		} else if robs.Prn[0] == 'E' {
			signh = signHeader.EHeader
		} else {
			utils.Log.Warnf("未知的卫星%s", robs.Prn)
			continue
		}

		sb.WriteString(robs.Prn)
		for i := 0; i < len(signh); i++ {
			signV := signh[i]
			fv := robs.PseV[signV]

			str := PrintRinexFV(fv, 3, 14)
			str += "  " //LLI

			str += PrintRinexFV(robs.L[signV], 3, 14)
			if robs.L[signV] != 0 {
				v := byte(0)
				if this.PreMap != nil && len(this.PreMap) > 0 {
					preObs := this.PreMap[k]
					if preObs != nil {
						a, p := fn_lli_a(int(preObs.LokT[signV]))
						b, n := fn_lli_a(int(robs.LokT[signV]))
						dt := int(this.TOW - this.PreTOW)

						if (p > n) ||
							(p == n && dt >= a) ||
							(p < n && b > p && dt >= (n+b-p)) || // if（p＜n）and （b＞p）and（dt≥（n+b-p））
							(p < n && b <= p && dt > n) || // if（p＜n）and （b≤p）and（dt＞n）
							(p < n && b > p && n < dt && dt < (n+b-p)) { // if（p＜n）and （b＞p）and（n＜dt＜（n+b-p）） 可能失锁

							v = byte(utils.SetBitValue0(uint64(v), 0, true))
							if robs.HalfC[signV] == 1 {
								v = byte(utils.SetBitValue0(uint64(v), 1, true))
							}
						}
					}
				}
				str += fmt.Sprintf("%d ", v) //LLI
			} else {
				str += "  "
			}

			str += PrintRinexFV(robs.Dop[signV], 3, 14)
			str += "  " //LLI SSI

			str += PrintRinexFV(robs.Snr[signV], 3, 14)
			str += "  " //LLI SSI
			sb.WriteString(str)
		}
		sb.WriteString("\n")
	}

	return len(prns)
}

func (this *EpochRinexObs) ToRinex3String(signHeader *RinexHeader) (int, string) {
	var sb utils.BytesBuilder
	n := this.WriteRinex3String(signHeader, &sb)
	return n, sb.String()
}
